package za.co.chris.traintimes.database.management;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

public class SqlLietEntityManager implements EntityManager {

	private SQLiteDatabase database;

	// public SqlLietEntityManager() {
	// this.database =;
	// }
	// public void open() throws SQLException {
	// database = dbHelper.getWritableDatabase();
	// }
	//
	// public void close() {
	// dbHelper.close();
	// }

	@Override
	public long insertElement(DatabaseElement e) {
		long insertId = database.insert(e.getClass().getName(), null, e.prepareForCommit());
		return insertId;
	}

	@Override
	public <T> T getElement(int id, T entityType) {
		return fetchAndWrapElements(entityType, "_id = " + id).get(0);
	}

	@Override
	public <T> List<T> getAllElements(T entityType) {
		return fetchAndWrapElements(entityType, null);
	}

	@SuppressWarnings({ "unchecked" })
	private <T> List<T> fetchAndWrapElements(T entityType, String selection) {
		T entity = null;
		Cursor cursor = null;
		List<T> entityList = new ArrayList<T>();
		Field[] fields = entityType.getClass().getDeclaredFields();
		String[] columnList = getColumnList(fields);
		String tableName = entityType.getClass().getSimpleName();

		cursor = databaseQuery(tableName, columnList, selection);

		cursor.moveToFirst();

		while (!cursor.isAfterLast()) {
			try {
				entity = (T) newElement(entityType);
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
			for (Field field : fields) {
				try {
					setField(field, cursor, entity);
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}

			}
			entityList.add(entity);
		}
		cursor.close();
		return entityList;
	}

	private <T> Object newElement(T entityType) throws InstantiationException, IllegalAccessException {
		return entityType.getClass().newInstance();
	}

	private String[] getColumnList(Field[] fields) {
		String[] columns = new String[fields.length];
		for (int i = 0; i < fields.length; i++) {
			columns[i] = fields[i].getName();
		}
		return columns;
	}

	private void setField(Field field, Cursor cursor, Object parent) throws IllegalArgumentException, IllegalAccessException {
		String columnName = field.getName();
		int columnIndex = cursor.getColumnIndex(columnName);
		Class<?> fieldType = field.getType();
		int columnType = cursor.getType(columnIndex);

		if (columnType == Cursor.FIELD_TYPE_FLOAT && Float.TYPE == fieldType) {
			field.setFloat(parent, cursor.getLong(columnIndex));
		} else if (columnType == Cursor.FIELD_TYPE_INTEGER && Integer.TYPE == fieldType) {
			field.setInt(parent, cursor.getInt(columnIndex));
		} else if (columnType == Cursor.FIELD_TYPE_STRING && String.class == fieldType) {
			field.set(parent, cursor.getString(columnIndex));
		} else {
			// print error
		}

	}

	public Cursor databaseQuery(String tableName, String[] columnList) {
		return databaseQuery(tableName, columnList, null);
	}

	public Cursor databaseQuery(String tableName, String[] columnList, String selection) {
		return databaseQuery(tableName, columnList, selection, null);
	}

	public Cursor databaseQuery(String tableName, String[] columnList, String selection, String[] argList) {
		return databaseQuery(tableName, columnList, selection, argList, null);
	}

	public Cursor databaseQuery(String tableName, String[] columnList, String selection, String[] argList, String groupBy) {
		return databaseQuery(tableName, columnList, selection, argList, groupBy, null);
	}

	public Cursor databaseQuery(String tableName, String[] columnList, String selection, String[] argList, String groupBy, String having) {
		return databaseQuery(tableName, columnList, selection, argList, groupBy, having, null);
	}

	public Cursor databaseQuery(String tableName, String[] columnList, String selection, String[] argList, String groupBy, String having, String orderBy) {
		return database.query(tableName, columnList, selection, argList, groupBy, having, orderBy);
	}
}
